package epoch.db.gamedb;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import epoch.db.gamedb.dialect.Dialect;
import epoch.db.gamedb.dialect.MysqlDialect;

/**
 * 数据库配置项
 * @author will
 * @date 2016年3月24日 下午2:08:48
 */
public class Config {
	
	private static Logger log = LogManager.getLogger(Config.class);

	//配置名称
	String name;
	//数据源
	DataSource dataSource;
	//默认mysql
	public Dialect dialect = new MysqlDialect();
	//是否显示sql
	boolean showSql = false;
	//是否调试模式
	boolean devMode = false;
	//事务级别
	int transactionLevel=Connection.TRANSACTION_REPEATABLE_READ;
	//缓存
	IDBCache cache = new DBCache();
	//实体和config的映射
	private static Map<Class<? extends Entity>, Config> modelToConfig = new HashMap<Class<? extends Entity>, Config>();
	//数据库连接
	private final ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
	
	/**
	 * 构造函数
	 * @param name
	 * @param dataSource
	 */
	public Config(String name, DataSource dataSource){
		this(name, dataSource,false);
	}
	
	/**
	 * 构造函数
	 * @param name
	 * @param dataSource
	 */
	public Config(String name, DataSource dataSource, boolean showSql){
		this.name = name;
		this.dataSource = dataSource;
		this.showSql = showSql;
	}

	public static Config getConfig(String configName) {
		List<Config> configs = new ArrayList<>(modelToConfig.values());
		for(Config conf : configs){
			if(conf.name.equals(configName)){
				return conf;
			}
		}
		return null;
	}

	public String getDefaultPrimaryKey() {
		return "id";
	}
	
	static void addModelToConfigMapping(Class<? extends Entity> modelClass, Config config) {
		modelToConfig.put(modelClass, config);
	}



	public Connection getConnection() throws SQLException {
		Connection conn = threadLocal.get();
		if (conn != null)
			return conn;
		return showSql ? new SqlReporter(dataSource.getConnection()).getConnection() : dataSource.getConnection();
	}

	public String getName() {
		return name;
	}

	public IDBCache getCache() {
		return cache;
	}

	public int getTransactionLevel() {
		return transactionLevel;
	}

	public void removeThreadLocalConnection() {
		threadLocal.remove();
		
	}

	public void setThreadLocalConnection(Connection conn) {
		threadLocal.set(conn);
	}

	public Connection getThreadLocalConnection() {
		return threadLocal.get();
	}

	public boolean isInTransaction() {
		return threadLocal.get() != null;
	}
	
	/**
	 * Close ResultSet、Statement、Connection
	 * ThreadLocal support declare transaction.
	 */
	public final void close(ResultSet rs, Statement st, Connection conn) {
		if (rs != null) {try {rs.close();} catch (SQLException e) {log.error(e.getMessage(), e);}}
		if (st != null) {try {st.close();} catch (SQLException e) {log.error(e.getMessage(), e);}}
		
		if (threadLocal.get() == null) { // in transaction if conn in threadlocal
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					throw new ActiveRecordException(e);
				}
			}
		}
	}
	
	public final void close(Statement st, Connection conn) {
		if (st != null) {
			try {
				st.close();
			} catch (SQLException e) {
				log.error(e.getMessage(), e);
			}
		}		
		if (threadLocal.get() == null) {	// in transaction if conn in threadlocal
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					throw new ActiveRecordException(e);
				}
			}
		}
	}
	
	public final void close(Connection conn) {
		if (threadLocal.get() == null){		// in transaction if conn in threadlocal
			if (conn != null){
				try {
					conn.close();
					//增加连接关闭日志
				} catch (SQLException e) {
					throw new ActiveRecordException("close db connection err!",e);
				}
			}
		}
	}
}
